1Writer 過去タスク検索
1. ポップアップを表示し、キーワード入力を求める
2. 過去の日次ノート(タイトルがYYYY-MM-DD形式のノート)を検索してリスト表示
リスト表示で、1行目にタイトル、2行目に日付、開始時刻、終了時刻、実績値をサブタイトルとして表示。見積時間の表示はやめた。
code:js
// 過去データ検索
const maxDaysToSearch = 15; // 検索範囲を1ヶ月に制限
const maxTasksToFind = 30; // 検索するタスクの上限を設定
let originalFilePath; // 元々開いていたファイルのパスを保持
// 検索キーワードをユーザーに入力させる
function promptUserForKeywords() {
return new Promise((resolve) => {
ui.input("タスク検索", "", "検索キーワードを入力してください(スペースで区切るとAND検索)", "default", (input) => {
if (input) {
resolve(input.split(" ")); // スペースで分割してキーワード配列に
} else {
resolve(null); // キャンセルされた場合
}
});
});
}
// 指定された日付のノートを開き、その内容を取得する
function getNoteForDate(folderPath, dateString) {
return new Promise((resolve) => {
const filePath = ${folderPath}/${dateString}.md; // 日付ベースのファイル名
editor.openFile(filePath, "edit", (success) => {
if (success) {
const noteText = editor.getText();
resolve(noteText); // ファイルが開けた場合、内容を返す
} else {
resolve(null); // ファイルが開けなかった場合、null を返す
}
});
});
}
// 行がタスクかどうかを判定する関数(タスクは - [x] で始まる)
function isTask(line) {
return line.startsWith("- x "); }
// 行にすべてのキーワードが含まれているかを判定(AND検索)
function containsKeywords(line, keywords) {
return keywords.every(keyword => line.toLowerCase().includes(keyword.toLowerCase()));
}
// 指定フォルダ内でタスクを検索する
async function searchTasks(keywords, folderPath) {
let foundTasks = [];
let currentDate = new Date(); // 現在の日付を取得
let daysChecked = 0;
while (foundTasks.length < maxTasksToFind && daysChecked < maxDaysToSearch) {
// YYYY-MM-DD形式で日付をフォーマット
const dateString = currentDate.toISOString().split('T')0; const note = await getNoteForDate(folderPath, dateString);
if (note) {
const lines = note.split('\n');
for (const line of lines) {
if (isTask(line) && containsKeywords(line, keywords)) {
foundTasks.push({ date: dateString, task: line });
if (foundTasks.length === maxTasksToFind) break;
}
}
}
// 日付を前日に設定
currentDate.setDate(currentDate.getDate() - 1);
daysChecked++;
}
return foundTasks;
}
// タスク行を解析し、開始時刻、終了時刻、実績時間、見積時間、タスク名を抽出する
function parseTaskLine(line) {
// 以下の正規表現を使って、タスクの各要素を抽出
const taskRegex = /^- \x\ (\d{2}:\d{2})-(\d{2}:\d{2})(?:\s+(\d+)?\\?(\d+)?\s+)?(.+)$/; const match = line.match(taskRegex);
if (match) {
return {
startTime: match1 || null, // 開始時刻 endTime: match2 || null, // 終了時刻 actualTime: match3 || null, // 実績時間 estimatedTime: match4 || null, // 見積時間 taskName: match5 ? match5.trim() : "不明" // タスク名 };
} else {
return null; // フォーマットが一致しない場合
}
}
// タスクをリスト形式で表示する
function displayTasks(tasks) {
if (tasks.length === 0) {
ui.hudError("該当するタスクが見つかりませんでした。");
} else {
const taskList = tasks.map(task => {
const parsedTask = parseTaskLine(task.task);
if (parsedTask) {
// タスク名をタイトルとして設定
const title = ${parsedTask.taskName};
// サブタイトル部分を、存在するデータだけで作成
let subtitleParts = [${task.date} ];
if (parsedTask.startTime && parsedTask.endTime) {
subtitleParts.push(${parsedTask.startTime}-${parsedTask.endTime});
}
if (parsedTask.actualTime||parsedTask.estimatedTime) {
subtitleParts.push(' (');
}
if (parsedTask.actualTime) {
subtitleParts.push(${parsedTask.actualTime});
}
// if (parsedTask.estimatedTime) {
// subtitleParts.push(${parsedTask.estimatedTime});
// }
if (parsedTask.actualTime||parsedTask.estimatedTime) {
subtitleParts.push(')');
}
const subtitle = subtitleParts.join('');
return { title, subtitle };
} else {
return { title: 不明, subtitle: ${task.date} }; // 解析できない場合
}
});
ui.list("検索結果", taskList.map(t => ${t.title}||${t.subtitle}), false, (selectedTask) => {
if (selectedTask) {
ui.hudSuccess(選択されたタスク: ${selectedTask});
}
});
}
}
// 元々開いていたファイルを再度開く
function reopenOriginalFile() {
if (originalFilePath) {
editor.openFile(originalFilePath, "edit", (success) => {
if (!success) {
ui.hudError("元のファイルを開けませんでした。");
}
});
}
}
// メイン処理
async function main() {
const folderPath = editor.getFolderPath(); // パスを確認して指定する
const filePath = editor.getFileName();
originalFilePath = folderPath + "/" + filePath; // 現在開いているファイルを保存
const keywords = await promptUserForKeywords();
if (!keywords) {
ui.hudError("検索キーワードが入力されませんでした。");
return;
}
// 手動でフォルダパスを指定する(必要に応じて)
const tasks = await searchTasks(keywords, folderPath); // タスクを検索
displayTasks(tasks); // 結果を表示
// 最後に元々開いていたファイルを再度開く
reopenOriginalFile();
}
// 実行
main();